#define TRACE
using System;
using System.Xml;
using System.Data;
using System.Configuration;
using System.Data.SqlTypes;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Globalization;

using System.IO;
using System.Text;

/*=====================================================================
This file is part of the Microsoft SQL Server Code Samples.
Copyright (C) Microsoft Corporation.  All rights reserved.

This source code is intended only as a supplement to Microsoft
Development Tools and/or on-line documentation.  See these other
materials for detailed information regarding Microsoft code samples.

THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

==================================================================== */
namespace Microsoft.Samples.SqlServer
{
    /// <summary>
    /// This class takes care of creating a Ordering Request message and sending it to the Ordering Service.
    /// </summary>
    public class ExtendedOrderProcessing
    {
        #region Constant Declarations
        static readonly decimal TAX_RATE = 0.1m;
        #endregion

        //No special action necessary in the constructor
        public ExtendedOrderProcessing()
        {
        }

        #region Post Sales Order
        /*
         * Send the OrderingRequest message to the Ordering Service and
         * empty the shopping cart.
         */
        public void PostSalesOrder(int orderId, string customerId, OrdersDB ordersDatabase)
        {
            // Format as XML
            XmlDocument xd = BuildOrderingRequestMessage(orderId, customerId, ordersDatabase);

            SqlConnection conn = null;
            SqlTransaction tran = null;

            try
            {
                // Connect to Sql Server.
                conn = new SqlConnection(Constants.ConnectionString);
                conn.Open();

                tran = conn.BeginTransaction();
                Service storefrontService = new Service(Constants.StorefrontService, conn, tran);

                // Initiate a conversation
                Conversation dialog = storefrontService.BeginDialog(
                    Constants.OrderingService,
                    null,
                    Constants.OrderingContract,
                    TimeSpan.FromMinutes(15), false, conn, tran);

                string msgString = xd.InnerXml;
                MemoryStream body = new MemoryStream(Encoding.ASCII.GetBytes(msgString));
                Message message = new Message(Constants.OrderingRequestMessageType, body);

                // Send the message to the ordering service
                dialog.Send(message, conn, tran);

                // Message isn't sent until transaction has been committed
                tran.Commit();

                // Not expecting a response so close the dialog
                dialog.End(conn, tran);
            }
            catch (Exception e)
            {
                if (tran != null)
                {
                    tran.Rollback();
                }
                throw e;
            }
            finally
            {
                // Close the connection.
                if (conn != null)
                {
                    if (conn.State == ConnectionState.Open)
                    {
                        conn.Close();
                    }
                }
            }
        }    
        
        #endregion

        #region Build Ordering Request Message
        /*
         * Create the XML OrderingRequest message.
         */
        private XmlDocument BuildOrderingRequestMessage(int salesOrderId, string customerId, OrdersDB ordersDatabase)
        {
            XmlDocument xd = new XmlDocument();
            XmlElement root = xd.CreateElement(Constants.XmlNamespacePrefix, Constants.XmlOrderingRequestRoot, Constants.XmlOrderingRequestNamespace);
            xd.AppendChild(root);
            
            XmlElement levelOne, levelTwo;
            
            levelOne = xd.CreateElement(Constants.XmlNamespacePrefix, Constants.XmlSalesOrderID, Constants.XmlOrderingRequestNamespace);
            levelOne.InnerText=salesOrderId.ToString(CultureInfo.InvariantCulture);
            root.AppendChild(levelOne);

            levelOne = xd.CreateElement(Constants.XmlNamespacePrefix, Constants.XmlCustomerID, Constants.XmlOrderingRequestNamespace);
            levelOne.InnerText = customerId.ToString(CultureInfo.InvariantCulture);
            root.AppendChild(levelOne);

            // Currently use address information is not being collected so just using the empty string
            levelOne = xd.CreateElement(Constants.XmlNamespacePrefix, Constants.XmlBillToAddressID, Constants.XmlOrderingRequestNamespace);
            levelOne.InnerText=""; //Need to fill in the address
            root.AppendChild(levelOne);
            
            levelOne = xd.CreateElement(Constants.XmlNamespacePrefix, Constants.XmlShipToAddressID, Constants.XmlOrderingRequestNamespace);
            levelOne.InnerText=""; //Need to fill in the address
            root.AppendChild(levelOne);

            // Temporarily set the current culture to US-EN since extended processing will be done in US Dollars
            CultureInfo oldCulture = CultureInfo.CurrentUICulture;
            OrderDetails details = null;
            try
            {
                WorldReady.SetCulture(WorldReady.USCulture);
                details = ordersDatabase.GetOrderDetails(salesOrderId, customerId);
            }
            finally
            {
                WorldReady.SetCulture(oldCulture);
            }

            // Get the subtotal                           
            String subTotal = details.OrderTotal;
            levelOne = xd.CreateElement(Constants.XmlNamespacePrefix, Constants.XmlSubtotal, Constants.XmlOrderingRequestNamespace);
            levelOne.InnerText=subTotal; 
            root.AppendChild(levelOne);

            decimal subTotalValue = decimal.Parse(subTotal.Trim().Substring(1), WorldReady.USCulture);
            decimal taxAmount = subTotalValue * TAX_RATE;
            levelOne = xd.CreateElement(Constants.XmlNamespacePrefix, Constants.XmlTaxAmount, Constants.XmlOrderingRequestNamespace);
            levelOne.InnerText = taxAmount.ToString(CultureInfo.InvariantCulture);
            root.AppendChild(levelOne);

            decimal totalDue = subTotalValue + taxAmount;
            levelOne = xd.CreateElement(Constants.XmlNamespacePrefix, Constants.XmlTotalDue, Constants.XmlOrderingRequestNamespace);
            levelOne.InnerText = totalDue.ToString(CultureInfo.InvariantCulture);
            root.AppendChild(levelOne);
            
            levelOne = xd.CreateElement(Constants.XmlNamespacePrefix, Constants.XmlOrderDate, Constants.XmlOrderingRequestNamespace);
            levelOne.InnerText = DateTime.Now.ToString(CultureInfo.InvariantCulture);
            root.AppendChild(levelOne);
                
            // Loop through each line item and add it to the document
            string productId, quantity, lineTotal;
            int lineNumber = 0;
            
            foreach (DataRow dr in details.OrderItems.Tables[0].Rows)
            {
                // This tag encloses the line items
                levelOne = xd.CreateElement(Constants.XmlNamespacePrefix, Constants.XmlLineItem, Constants.XmlOrderingRequestNamespace);
                levelOne.InnerText=""; 
                root.AppendChild(levelOne);

                lineNumber ++;
                productId = dr["ProductID"].ToString();
                quantity = dr["OrderQty"].ToString();
                lineTotal = dr["ExtendedAmount"].ToString();

                // Add the XML for line items
                levelTwo = xd.CreateElement(Constants.XmlNamespacePrefix, Constants.XmlLineNumber, Constants.XmlOrderingRequestNamespace);
                levelTwo.InnerText = lineNumber.ToString(CultureInfo.InvariantCulture);
                levelOne.AppendChild(levelTwo);

                levelTwo = xd.CreateElement(Constants.XmlNamespacePrefix, Constants.XmlProductID, Constants.XmlOrderingRequestNamespace);
                levelTwo.InnerText = productId;
                levelOne.AppendChild(levelTwo);

                levelTwo = xd.CreateElement(Constants.XmlNamespacePrefix, Constants.XmlQuantity, Constants.XmlOrderingRequestNamespace);
                levelTwo.InnerText = quantity;
                levelOne.AppendChild(levelTwo);

                levelTwo = xd.CreateElement(Constants.XmlNamespacePrefix, Constants.XmlLineTotal, Constants.XmlOrderingRequestNamespace);
                levelTwo.InnerText = lineTotal;
                levelOne.AppendChild(levelTwo);
            }

            return xd;
        }

        #endregion

    }
}
